import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { DragControls } from "three/examples/jsm/controls/DragControls.js";
import { TransformControls } from "three/examples/jsm/controls/TransformControls.js";
import { STLLoader } from "three/addons/loaders/STLLoader.js";
// import MODELBOX_SDK from "modelbox-sdk";
let scene: THREE.Scene | THREE.Mesh | any,
  camera: THREE.PerspectiveCamera,
  renderer: THREE.WebGLRenderer,
  controls: any;
let meshList = [];
let currentModel: THREE.Object3D;
export const initThree = (dom: any) => {
  // 初始化场景
  scene = new THREE.Scene();
  scene.background = new THREE.Color(0xbfe3dd);
  // 初始化相机
  camera = new THREE.PerspectiveCamera(
    75,
    dom.value.clientWidth / dom.value.clientHeight,
    0.1,
    1000
  );
  camera.position.z = 5;
  // 初始化渲染器
  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(dom.value.clientWidth, dom.value.clientHeight);
  dom.value.appendChild(renderer.domElement);
  renderer.shadowMap.enabled = true;
  renderer.shadowMap.type = THREE.PCFSoftShadowMap;
  // 添加控制器
  controls = new OrbitControls(camera, renderer.domElement);
  controls.update();
  // 添加光源
  const light1 = new THREE.SpotLight(0xffffff, 0.5);
  const light2 = new THREE.DirectionalLight(0x00ffff, 1);
  const light3 = new THREE.DirectionalLight(0xffffff, 1);
  light1.position.set(-4, 0, 0);
  light2.position.set(4, -5, -3);
  light3.position.set(-4, 5, 3);
  scene.add(light1);
  scene.add(light2);
  scene.add(light3);
  // 坐标轴
  const axesHelper = new THREE.AxesHelper(6);
  scene.add(axesHelper);
  // 创建并添加 GridHelper
  const size = 50;
  const divisions = 50;
  const gridHelper = new THREE.GridHelper(size, divisions);
  scene.add(gridHelper);
  initOrigin();
  // 动画循环
  function animate() {
    requestAnimationFrame(animate);
    // cube.rotation.x += 0.01
    // cube.rotation.y += 0.01
    renderer.render(scene, camera);
  }
  animate();
  initDragControls();
  // 响应式处理窗口大小变化
  window.addEventListener("resize", () => {
    dom && (camera.aspect = dom.value.clientWidth / dom.value.clientHeight);
    camera.updateProjectionMatrix();
    dom && renderer.setSize(dom.value.clientWidth, dom.value.clientHeight);
  });
};
// 添加立方体
const initOrigin = () => {
  const geometry = new THREE.BoxGeometry();
  const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
  const cube = new THREE.Mesh(geometry, material);
  cube.position.set(3, 0.8, 0.3);
  cube.scale.set(0.5, 0.5, 0.5);
  scene.add(cube);

  // console.log("three", THREE);
  // 直接创建 BufferGeometry
  const geometry2 = new THREE.BoxGeometry(3, 1, 1); // 现在已更名为 BoxGeometry

  // 创建网格
  const mesh = new THREE.Mesh(geometry2, material);
  mesh.position.set(3, 0.3, 0.3);
  mesh.scale.set(0.5, 0.5, 0.5);
  scene.add(mesh);
};
export const readStepFile = async (file: File, hasEdges: Boolean) => {
  // 使用FileReader读取文件为ArrayBuffer
  console.log("start", new Date().getTime());
  const reader = new FileReader();
  const arrayBuffer = await new Promise((resolve, reject) => {
    reader.onload = () => resolve(reader.result);
    reader.onerror = reject;
    reader.readAsArrayBuffer(file);
  });

  let occt = await (window as any).occtimportjs();
  const occtInstance = await occt.ready;
  // 解析STEP文件
  const result = await occtInstance.ReadStepFile(
    new Uint8Array(arrayBuffer as ArrayBuffer),
    null
  );
  // console.log("result", result);
  if (!result.success) {
    throw new Error("STEP文件解析失败");
  }
  console.log("e n d", new Date().getTime());
  meshList = [];
  if (currentModel) {
    scene.remove(currentModel);
  }
  const mainObject = new THREE.Object3D();
  const group = new THREE.Group();
  for (let resultMesh of result.meshes) {
    const { mesh, edges } = buildMesh(resultMesh, true);
    group.add(mesh);
    if (hasEdges && edges) group.add(edges);
    meshList.push({ uuid: mesh.uuid, visible: mesh.visible });
  }
  mainObject.add(group);
  // console.log("mainObject", mainObject);
  currentModel = mainObject;
  scene.add(mainObject);
  return meshList;
};
const buildMesh = (geometryMesh: any, showEdges: any) => {
  const geometry = new THREE.BufferGeometry();

  geometry.setAttribute(
    "position",
    new THREE.Float32BufferAttribute(geometryMesh.attributes.position.array, 3)
  );

  if (geometryMesh.attributes.normal)
    geometry.setAttribute(
      "normal",
      new THREE.Float32BufferAttribute(geometryMesh.attributes.normal.array, 3)
    );

  geometry.name = geometryMesh.name;

  const index = Uint32Array.from(geometryMesh.index.array);
  geometry.setIndex(new THREE.BufferAttribute(index, 1));

  const outlineMaterial = new THREE.LineBasicMaterial({ color: 0x000000 });
  const defaultMaterial = new THREE.MeshPhongMaterial({
    color: geometryMesh.color
      ? new THREE.Color(
          geometryMesh.color[0],
          geometryMesh.color[1],
          geometryMesh.color[2]
        )
      : 0xcccccc,
    specular: 0,
  });

  let materials = [defaultMaterial];
  const edges = showEdges ? new THREE.Group() : null;

  if (geometryMesh.brep_faces && geometryMesh.brep_faces.length > 0) {
    for (let faceColor of geometryMesh.brep_faces) {
      const color = faceColor.color
        ? new THREE.Color(
            faceColor.color[0],
            faceColor.color[1],
            faceColor.color[2]
          )
        : defaultMaterial.color;
      materials.push(
        new THREE.MeshPhongMaterial({ color: color, specular: 0 })
      );
    }
    const triangleCount = geometryMesh.index.array.length / 3;

    let triangleIndex = 0;
    let faceColorGroupIndex = 0;

    while (triangleIndex < triangleCount) {
      const firstIndex = triangleIndex;
      let lastIndex = null;
      let materialIndex = null;
      if (faceColorGroupIndex >= geometryMesh.brep_faces.length) {
        lastIndex = triangleCount;
        materialIndex = 0;
      } else if (
        triangleIndex < geometryMesh.brep_faces[faceColorGroupIndex].first
      ) {
        lastIndex = geometryMesh.brep_faces[faceColorGroupIndex].first;
        materialIndex = 0;
      } else {
        lastIndex = geometryMesh.brep_faces[faceColorGroupIndex].last + 1;
        materialIndex = faceColorGroupIndex + 1;
        faceColorGroupIndex++;
      }
      geometry.addGroup(
        firstIndex * 3,
        (lastIndex - firstIndex) * 3,
        materialIndex
      );
      triangleIndex = lastIndex;

      if (edges) {
        const innerGeometry = new THREE.BufferGeometry();
        innerGeometry.setAttribute("position", geometry.attributes.position);

        if (geometryMesh.attributes.normal)
          innerGeometry.setAttribute("normal", geometry.attributes.normal);

        innerGeometry.setIndex(
          new THREE.BufferAttribute(
            index.slice(firstIndex * 3, lastIndex * 3),
            1
          )
        );

        const innerEdgesGeometry = new THREE.EdgesGeometry(innerGeometry, 180);
        const edge = new THREE.LineSegments(
          innerEdgesGeometry,
          outlineMaterial
        );

        edges.add(edge);
      }
    }
  }

  const mesh = new THREE.Mesh(
    geometry,
    materials.length > 1 ? materials : materials[0]
  );
  mesh.name = geometryMesh.name;

  if (edges) edges.renderOrder = mesh.renderOrder + 1;

  return { mesh, geometry, edges };
};
export const dispose = () => {
  renderer.dispose();
};
export const stlLoader = (file: File) => {
  const loader = new STLLoader();
  const reader = new FileReader();
  reader.readAsArrayBuffer(file);
  reader.onload = function () {
    try {
      // 解析STL文件
      const geometry = loader.parse(reader.result as string);

      // 创建材质
      const material = new THREE.MeshStandardMaterial({
        color: 0x2196f3,
        metalness: 0.3,
        roughness: 0.4,
        wireframe: false,
      });

      // 创建网格
      let model = new THREE.Mesh(geometry, material);

      // 计算法线（使光照效果正确）
      geometry.computeVertexNormals();

      // 设置初始旋转速度
      model.userData.rotationSpeed = 0.01;
      model.position.set(0, 0.5, 0);
      model.scale.set(2, 2, 2);
      // 添加到场景
      scene.add(model);
    } catch (error) {
      console.error("STL加载错误:", error);
      // status.textContent = '加载失败: ' + error.message;
      // status.className = 'status error';
      // createPlaceholderModel();
    }
  };
};
// export const ModelBox = (file: File) => {
//   // modelbox-sdk:待测试，本地无法跨域，待服务端部署测试。。。https://api.mobox3d.com/file/Fileapi/create
//   let name = "name-test";
//   let comment = "name-comment";
//   let config = {};
//   MODELBOX_SDK.updateToken("5c06b6b8a548d8911e3ccdbdc518fac6");
//   MODELBOX_SDK.uploadModel({
//     file: file,
//     type: file.name.split(".")[1],
//     config: {
//       name: name,
//       comment: comment,
//     },
//     modelConfig: config,
//     success: function (res: any) {
//       console.log("res", res);
//       // layui.layer.close(layerIndex);
//       // res.iframe_url 表示嵌入网页的 url
//       // res.editor_url 表示编辑器网页 url
//       // res.source_file_url 表示源资源的下载 url
//       window.open(res.iframe_url);
//       console.log(res);
//     },
//     error: function (msg: string) {
//       console.error(msg); // 错误信息
//     },
//   });
// };
export function initDragControls() {
  // 添加平移控件
  const transformControls = new TransformControls(camera, renderer.domElement);
  scene.add(transformControls);

  const dragControls = new DragControls([], camera, renderer.domElement);
  dragControls.enabled = false;
  // 鼠标略过事件
  dragControls.addEventListener("hoveron", function (event: any) {
    // 让变换控件对象和选中的对象绑定
    transformControls.attach(event.object);
  });
  // 开始拖拽
  dragControls.addEventListener("dragstart", function () {
    controls.enabled = false;
  });
  // 拖拽结束
  dragControls.addEventListener("dragend", function () {
    controls.enabled = true;
  });
  function abledDrag(isGroup: Boolean) {
    // 过滤不是 Mesh 的物体,例如辅助网格对象
    const objects = [];
    for (let i = 0; i < scene.children.length; i++) {
      if ((scene.children[i] as any).isMesh && !isGroup) {
        objects.push(scene.children[i]);
        dragControls.transformGroup = false;
      } else if (
        scene.children[i].isObject3D &&
        scene.children[i].children.length &&
        isGroup
      ) {
        objects.push(scene.children[i].children[0]);
        dragControls.transformGroup = true;
      }
    }
    dragControls.objects = objects;
    dragControls.enabled = true;
    console.log("initDragControls ready", scene.children);
  }
  function disabledDrag() {
    dragControls.objects = [];
    dragControls.enabled = false;
  }
  return { abledDrag, disabledDrag };
}
export function setVisible(uuid: string, visible: boolean) {
  for (let i = 0; i < scene.children.length; i++) {
    for (let j = 0; j < currentModel.children[0].children.length; j++) {
      if (currentModel.children[0].children[j].uuid == uuid) {
        currentModel.children[0].children[j].visible = visible;
        renderer.render(scene, camera);
        break;
      }
    }
    break;
  }
}
